---@class Battle.EntityGameObjectSystem:Battle.EntityComponent
local EntityGameObjectSystem = Battle.CreateClass("EntityGameObjectSystem",Battle.EntityComponent)
Battle.EntityGameObjectSystem = EntityGameObjectSystem

local HIDE_LAYER = LayerMask.NameToLayer("Hide")
local HERO_LAYER = LayerMask.NameToLayer("Hero")

function EntityGameObjectSystem:OnCreate()
    ---@type Animator
    self.animator = nil
    ---@type GameObject
    self.gameObject = GameObject.New("pawn")
    ---@type Transform
    self.transform = self.gameObject.transform
    ---@type UnityEngine.AnimationClip[]
    self.clipList = {}
    self.isPath = false
    self.destination = Vector3.New()
    self.delayRegAnimEventSkillList = {}
    Battle.SceneMgr.AddChild(self.transform)

    self:Register()
end
function EntityGameObjectSystem:OnInitialized()
    ---@type CEntity
    self.cEntity = self.gameObject:AddComponent(typeof(CEntity))
    self.cEntity:SetRotateSpeed(self.actor.rotateSpeed)
    self.cEntity:SetEntityId(self.actor.id)
    self.cEntity:SetEntityType(self.actor.actorType)
    self.cEntity:SetMoveSpeed(self.actor.attrSystem:GetSpeed())
    self.cEntity.bodyRadius = self.actor.radius
    self.cEntity:SetLuaTable(self)
    ---@type MoveSystem
    self.moveSystem = self.gameObject:GetComponent(typeof(MoveSystem))
    self.moveSystem.areaMask = Battle.SceneMgr.GetWorkAreaMask(self.actor)
end
function EntityGameObjectSystem:OnDestroy()
    
    Battle.PoolMgr.CancelLoad(self.LoadRequestId)
    Battle.PoolMgr.ReturnPrefabToPool(self.modelName, self.modelObj)
    self.modelName = ""
    if self.gameObject then
        destroy(self.gameObject)
    end
    self:UnRegister()

    self.clipList = nil
    self.gameObject = nil
    self.transform = nil
end
function EntityGameObjectSystem:Register()
    local eventSystem = self.actor.eventSystem
    eventSystem:Register(Battle.Event.ActorPosChanged,self.Event_PosChanged,self)
    eventSystem:Register(Battle.Event.ActorForwardChanged,self.Event_ForwardChanged,self)
    eventSystem:Register(Battle.Event.ActorAnimatorPlay,self.Event_AnimatorPlay,self)
    eventSystem:Register(Battle.Event.StopPathFind,self.Event_StopPathFind,self)
    eventSystem:Register(Battle.Event.StartPathFind,self.Event_StartPathFind,self)
    eventSystem:Register(Battle.Event.ActorDeadAnimFinished,self.Event_DeadAimFinished,self)
    eventSystem:Register(Battle.Event.ActorDead,self.Event_Dead,self)
    eventSystem:Register(Battle.Event.ActorEffectStateChange,self.Event_EffectStateChange,self)
    eventSystem:Register(Battle.Event.ActorSignChange,self.Event_SignChange,self)
    eventSystem:Register(Battle.Event.RegisterSkillFrameEvent,self.Event_RegisterSkillFrameEvent,self)
end
function EntityGameObjectSystem:UnRegister()
    local eventSystem = self.actor.eventSystem
    eventSystem:UnRegister(Battle.Event.ActorPosChanged,self.Event_PosChanged,self)
    eventSystem:UnRegister(Battle.Event.ActorForwardChanged,self.Event_ForwardChanged,self)
    eventSystem:UnRegister(Battle.Event.ActorAnimatorPlay,self.Event_AnimatorPlay,self)
    eventSystem:UnRegister(Battle.Event.StopPathFind,self.Event_StopPathFind,self)
    eventSystem:UnRegister(Battle.Event.StartPathFind,self.Event_StartPathFind,self)
    eventSystem:UnRegister(Battle.Event.ActorDeadAnimFinished,self.Event_DeadAimFinished,self)
    eventSystem:UnRegister(Battle.Event.ActorDead,self.Event_Dead,self)
    eventSystem:UnRegister(Battle.Event.ActorEffectStateChange,self.Event_EffectStateChange,self)
    eventSystem:UnRegister(Battle.Event.ActorSignChange,self.Event_SignChange,self)
    eventSystem:UnRegister(Battle.Event.RegisterSkillFrameEvent,self.Event_RegisterSkillFrameEvent,self)

end
function EntityGameObjectSystem:LoadModel()
    if self.isLoading then
        return
    end
    local name = DataTable.GetById("t_heroresources", self.actor.modelId, "f_HeroModel")
    name = Battle.HERO_PATH .. name
    if self.modelName == name then
        return
    end
    self.modelName = name
    self.isLoading = true
    self.LoadRequestId = Battle.PoolMgr.LoadPrefabFromPool(self.modelName, self.LoadCallback, self)
end
---@param go GameObject
function EntityGameObjectSystem:LoadCallback(go)
    if self.actor.isDestroyed then
        return
    end

    self.isLoaded = true
    ---@type GameObject
    self.modelObj = go
    self.modelObj:SetActive(true)
    self.modelObj.transform:SetParent(self.transform, false)
    local height = DataTable.GetById("t_hero",self.actor.modelId,"f_BattleFlightAltitude")
    Util.SetLocalPosition(self.modelObj, 0, height/100, 0)
    Util.SetLocalRotation(self.modelObj, 0, 90, 0)
    local cfg = DataTable.GetById("t_hero",self.actor.modelId)
    local scale = cfg.f_BattleSizeZoom/100
    Util.SetLocalScale(self.modelObj,scale,scale,scale)
    Util.SetObjectLayer(self.gameObject,HERO_LAYER)
    self.animator = self.modelObj:GetComponentInChildren (typeof(Animator))
    local skill = self.actor.skillSystem:GetNormalSkill()
    self.cEntity.attackRadius = skill == nil and 0 or skill.releaseRadius
    self.cEntity.searchRadius = self.actor.searchRadius
    self.gameObject.name = "p" .. self.actor.id
    self:InitAnimationEvent()

    if self.actor:IsUnitFly() then
        local tc = typeof(UnityEngine.CharacterController)
        local collider = go:GetComponent(tc)
        if not collider then
            collider = go:AddComponent(tc)
            collider.radius = self.actor.radius
            collider.height = 2
            collider.center = Vector3(0, 1, 0)
        end
    end
    if self.animator then
        self.actor.hitDuringTime = self:GetClipLength("hit")
    end
    --出生特效
    Battle.EffectShowMgr.PlayEffect("eff_chusheng",self.actor.pos,nil,1)

    if self.animName then
        self:AnimatorPlay(self.animName,self.animSkillId)
    end
    self:UpdateHide()
    self.actor.eventSystem:FireEvent(Battle.Event.ActorObjectCreate,Battle.EventArgs.EntityArgs:Create(self.actor))
end
function EntityGameObjectSystem:IsTran(transform)
    local flag = self.transform == transform
    if self.modelObj then
        flag = flag or self.modelObj.transform == transform
    end
    return flag
end
function EntityGameObjectSystem:GetTran()
    return self.transform
end
function EntityGameObjectSystem:SetPos(x, y, z)
    if self.moveSystem then
        self.moveSystem:MoveTo(x,y,z)
    end
end
function EntityGameObjectSystem:InitAnimationEvent()
    -- 获取所有的clips
    if not self.animator then return end
    local clips = self.animator.runtimeAnimatorController.animationClips;
    if (nil == clips or clips.Length <= 0) then
        return
    end
    for i = 0, clips.Length - 1 do
        local clip = clips[i]
        if clip ~= nil then
            self.clipList[clip.name] = clip
        end
    end
    ---@type CAnimatorEvent
    local eventLis = self.animator.gameObject:GetComponent(typeof(CAnimatorEvent))
    if not eventLis then
        eventLis = self.animator.gameObject:AddComponent(typeof(CAnimatorEvent))
    end
    local skillSystem =  self.actor.skillSystem
    ---@type Battle.Skill[]
    local skillList = {skillSystem:GetNormalSkill(),skillSystem:GetSkill1()}
    for k,v in pairs(skillList) do
        self:InitAnimationEvent2(v)
    end
    for k,v in pairs(self.delayRegAnimEventSkillList) do
        self:InitAnimationEvent2(v)
    end
    table.clear(self.delayRegAnimEventSkillList)
end
---@param skill Battle.Skill
function EntityGameObjectSystem:InitAnimationEvent2(skill)
    if skill == nil then return end
    if self.animator == nil then
        table.insert(self.delayRegAnimEventSkillList,skill)
        return
    end
    local eventLis = self.animator.gameObject:GetComponent(typeof(CAnimatorEvent))
    local name,hitTime = self:GetAnimNameByTime(skill.skillData.animNameList,skill.skillData.hitDelayTime)
    if skill.skillData.hitDelayTime >= 0 then
        eventLis:AddEvent(name,"Hit",skill.skillId,hitTime)
    end
    if skill.skillData.f_CastMagicSE then
        eventLis:AddEvent(name,"ReleaseEff",skill.skillId,hitTime)
    end
end
function EntityGameObjectSystem:GetAnimNameByTime(animNameList,time)
    local len = 0
    for k,v in pairs(animNameList) do
        local l =self:GetClipLength(v)
        if time < len + l  then
            return v,time - len
        end
        len = len + l
    end
    return "",0
end
function EntityGameObjectSystem:GetClipLength(clipName)
    if string.IsEmpty(clipName) then
        return 0
    end
    local clip = self.clipList[clipName]
    if not clip then
        logError(self.modelName .. "找不到该动画,动画名： " .. clipName)
        return 0
    end
    return clip.length
end
function EntityGameObjectSystem:UpdateHide()
    local isHide = self.actor.effectStateSystem:IsHide()
    if isHide  then
        if self.actor.camp == Battle.CampType.Red then
            Util.SetObjectLayer(self.gameObject,HIDE_LAYER)
        else
            self.cEntity:SetHide(isHide)
        end
    else
        if self.actor.camp == Battle.CampType.Red then
            Util.SetObjectLayer(self.gameObject,HERO_LAYER)
        else
            self.cEntity:SetHide(isHide)
        end
    end
end
function EntityGameObjectSystem:StartRotate(forwardX,forwardY,forwardZ)
   self.cEntity:StartRotate(forwardX,forwardY,forwardZ)
end
function EntityGameObjectSystem:ShowOutLine(isShow)
    self.cEntity:SetOutLine(isShow)
end
function EntityGameObjectSystem:Event_PosChanged()
    Util.SetPosition(self.transform,self.actor.pos.x,self.actor.pos.y,self.actor.pos.z)
end
function EntityGameObjectSystem:Event_ForwardChanged()
    self.transform.forward = self.actor.forward
end
function EntityGameObjectSystem:GetAnimListLength(animNameList)
    local len = 0
    for k,v in pairs(animNameList) do
        len = len + self:GetClipLength(v)
    end
    return len
end
function EntityGameObjectSystem:AnimatorPlay(animName,skillId)
    self.animName = animName
    self.animSkillId = skillId
    local anim = self.animator
    if not anim then return end
    if skillId then
        local speed = 1
        local skill = self.actor.skillSystem:GetSkill(skillId)
        self.animName = skill.skillData.show.f_CastMagicAction
        if skill.skillData.skillType == Battle.SkillType.Normal then
            local len = self:GetAnimListLength(skill.skillData.animNameList)
            if len > 0 then
                speed = len/(skill.during*skill.speedRate)
            end
        end

        anim:SetFloat("attackSpeed",speed)
    end
    local animId = Battle.AnimationConfig[self.animName]
    if animId == nil then
        logError("动画id没有配置："..self.animName)
        return
    end
    anim:SetInteger("animation",animId)
    anim:SetTrigger("skillTrigger")
end
---@param args BattleEvent
function EntityGameObjectSystem:Event_AnimatorPlay(args)
    self:AnimatorPlay(args.animName,args.skillId)
end
function EntityGameObjectSystem:Event_StopPathFind()
    self.moveSystem:Stop()
end
---@param args BattleEvent
function EntityGameObjectSystem:Event_StartPathFind(args)
    local pos = args.pos
    self.destination:SetV(pos)
    self.isPath = true
    self.moveSystem:SetDestination(pos)
end
function EntityGameObjectSystem:Event_DeadAimFinished()
    Util.SetPosition(self.gameObject,1000,1000,1000)
end
function EntityGameObjectSystem:Event_Dead()
    self.cEntity:SetDie()
end
---@param args Battle.EntityEffectStateChangeArgs
function EntityGameObjectSystem:Event_EffectStateChange(args)
    if args.stateId == Battle.FighterStateEnum.GRASS_HIDE or args.stateId == Battle.FighterStateEnum.BUFF_HIDE then
        self:UpdateHide()
        return
    end
end
---@param args Battle.EntitySignChangeArgs
function EntityGameObjectSystem:Event_SignChange(args)
    if args.signId == Battle.BuffSignType.Stun then
        args.sender.aiSystem:SetBlackboardValue("stun",args.isAdd)
        return
    end
end
---@param args SkillArgs
function EntityGameObjectSystem:Event_RegisterSkillFrameEvent(args)
    self:InitAnimationEvent2(args.skill)
end
---c#回调
function EntityGameObjectSystem:ctol_PosChanged(x,y,z)
    self.actor.pos:Set(x,y,z)
    self.actor.eventSystem:FireEvent(Battle.Event.ActorPosChanged, Battle.EventArgs.EntityArgs:Create(self.actor))
end
---c#回调
function EntityGameObjectSystem:ctol_ForwardChanged(x,y,z)
    self.actor.forward:Set(x,y,z)
    self.actor.eventSystem:FireEvent(Battle.Event.ActorForwardChanged, Battle.EventArgs.EntityArgs:Create(self.actor))
end
---c#回调
function EntityGameObjectSystem:ctol_SetMoving(flag)
    self.actor:SetMoving(flag)
end
function EntityGameObjectSystem:SetGrass(id,isIn)
    self.actor:SetGrass(id,isIn)
end
function EntityGameObjectSystem:ctol_SkillAnimationEvent(eventId,eventValue)
    local action = eventId
    local skillId = tonumber(eventValue)
    local skill = self.actor.skillSystem:GetSkill(skillId)
    if not skill then
        logError("找不到技能："..tostring(skillId))
        return
    end
    skill:AnimationEvent(action,true)

end